
package com.way.filemanager.util;

import android.widget.ListView;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;

/**
 */

public class ScrollOverListView extends ListView {

    private static final String TAG = "ScrollOverListView";
    private static final boolean DEBUG = false;
    private int mLastY;
    private int mTopPosition;
    private int mBottomPosition;

    public ScrollOverListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public ScrollOverListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ScrollOverListView(Context context) {
        super(context);
        init();
    }

    private void init() {
        mTopPosition = 0;
        mBottomPosition = 0;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (DEBUG)
                Log.d(TAG, "onInterceptTouchEvent Action down");
            mLastY = (int) ev.getRawY();
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        final int y = (int) ev.getRawY();

        boolean isHandled = false;
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                if (DEBUG)
                    Log.d(TAG, "action down");
                mLastY = y;
                isHandled = mOnScrollOverListener.onMotionDown(ev);
                if (isHandled) {
                    break;
                }
                break;
            }

            case MotionEvent.ACTION_MOVE: {
                if (DEBUG)
                    Log.d(TAG, "action move");
                final int childCount = getChildCount();
                if (childCount == 0) {
                    break;
                }

                final int itemCount = getAdapter().getCount() - mBottomPosition;

                final int deltaY = y - mLastY;
                if (DEBUG)
                    Log.d(TAG, "lastY=" + mLastY + " y=" + y);

                final int firstTop = getChildAt(0).getTop();
                final int listPadding = getListPaddingTop();

                final int lastBottom = getChildAt(childCount - 1).getBottom();
                final int end = getHeight() - getPaddingBottom();

                final int firstVisiblePosition = getFirstVisiblePosition();

                isHandled = mOnScrollOverListener.onMotionMove(ev, deltaY);

                if (isHandled) {
                    break;
                }

                // DLog.d("firstVisiblePosition=%d firstTop=%d listPaddingTop=%d deltaY=%d",
                // firstVisiblePosition, firstTop, listPadding, deltaY);
                if (firstVisiblePosition <= mTopPosition && firstTop >= listPadding && deltaY > 0) {
                    if (DEBUG)
                        Log.d(TAG, "action move pull down");
                    isHandled = mOnScrollOverListener.onListViewTopAndPullDown(ev, deltaY);
                    if (isHandled) {
                        break;
                    }
                }

                // DLog.d("lastBottom=%d end=%d deltaY=%d", lastBottom, end,
                // deltaY);
                if (firstVisiblePosition + childCount >= itemCount && lastBottom <= end
                        && deltaY < 0) {
                    if (DEBUG)
                        Log.d(TAG, "action move pull up");
                    isHandled = mOnScrollOverListener.onListViewBottomAndPullUp(ev, deltaY);
                    if (isHandled) {
                        break;
                    }
                }
                break;
            }

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP: {
                if (DEBUG)
                    Log.d(TAG, "action move pull up");
                isHandled = mOnScrollOverListener.onMotionUp(ev);
                if (isHandled) {
                    break;
                }
                break;
            }
        }

        mLastY = y;
        if (isHandled) {
            return true;
        }
        return super.onTouchEvent(ev);
    }

    private OnScrollOverListener mOnScrollOverListener = new OnScrollOverListener() {

        @Override
        public boolean onListViewTopAndPullDown(MotionEvent event, int delta) {
            return false;
        }

        @Override
        public boolean onListViewBottomAndPullUp(MotionEvent event, int delta) {
            return false;
        }

        @Override
        public boolean onMotionDown(MotionEvent ev) {
            return false;
        }

        @Override
        public boolean onMotionMove(MotionEvent ev, int delta) {
            return false;
        }

        @Override
        public boolean onMotionUp(MotionEvent ev) {
            return false;
        }
    };

    // =============================== public method
    // ===============================
    public void setTopPosition(int index) {
        if (index < 0)
            throw new IllegalArgumentException("Top position must > 0");

        mTopPosition = index;
    }

    /**
     * @param index
     */
    public void setBottomPosition(int index) {
        if (index < 0)
            throw new IllegalArgumentException("Bottom position must > 0");

        mBottomPosition = index;
    }

    /**
     * @see OnScrollOverListener
     */
    public void setOnScrollOverListener(OnScrollOverListener onScrollOverListener) {
        mOnScrollOverListener = onScrollOverListener;
    }

    public interface OnScrollOverListener {

        boolean onListViewTopAndPullDown(MotionEvent event, int delta);

        boolean onListViewBottomAndPullUp(MotionEvent event, int delta);

        boolean onMotionDown(MotionEvent ev);

        boolean onMotionMove(MotionEvent ev, int delta);

        boolean onMotionUp(MotionEvent ev);

    }

}
